﻿// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;
using JetBrains.Annotations;

namespace SnapObjects.Data
{
    public class IndexStack<T>
    {
        private int _currIndex;
        private readonly IList<T> _items;

        public IndexStack()
        {
            _items = new List<T>();
            
            this.Init();
        }

        public IndexStack([NotNull] IEnumerable<T> collection) 
        {
            _items = new List<T>();
            foreach (var item in collection)
            {
                _items.Add(item);
            }
            
            this.Init();
        }

        public IndexStack(int capacity)
        {
            _items = new List<T>(capacity);

            this.Init();
        }

        public T CurrentItem { get; private set; }
        
        public T PreviousItem { get; private set; }
        
        private void Init()
        {
            _currIndex = _items.Count - 1;

            this.GenerateItem();
        }

        protected virtual void GenerateItem()
        {            
            this.CurrentItem = _currIndex >= 0 ? _items[_currIndex] : default;
            this.PreviousItem = _currIndex - 1 >= 0 ? _items[_currIndex - 1] : default;
        }
        
        public virtual void Push(T item)
        {
            if (_currIndex < 0 || _currIndex == _items.Count - 1)
            {
                _items.Add(item);  
                
                _currIndex = _items.Count - 1;
            }
            else
            {
                _currIndex++;
                _items[_currIndex] = item;
            }
            
            this.GenerateItem();
        }

        public virtual T Pop()
        {
            if (_currIndex < 0)
            {
                throw new IndexOutOfRangeException();
            }

            var item = _items[_currIndex];
            
            _currIndex--;
            
            this.GenerateItem();

            return item;
        }

        public virtual T Peek()
        {
            if (_currIndex >= 0)
            {
                return _items[_currIndex];
            }

            throw new IndexOutOfRangeException();
        }
        
        public virtual T Peek(int index)
        {
            if (index >= 0)
            {
                return _items[index];
            }

            throw new IndexOutOfRangeException();
        }

        public bool IsEmpty()
        {
            return _items.Count == 0;
        }
    }
}